package robocup.testing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Arrays;
import java.util.LinkedList;

import robocup.component.SConf;
import robocup.component.geometry.Circle;
import robocup.component.geometry.LineSegment;
import robocup.component.geometry.Vektor;
import robocup.component.geometry.analysers.PossibleBallsAfterPoweredAcc;
import robocup.component.geometry.analysers.ReachableArea;
import robocup.component.situations.ScoreSituation.ShotEvaluatorResults;
import robocup.component.situations.ScoreSituation.ShotEvaluatorResults.SHOT_VALUE;
import robocup.component.worldobjects.Ball;
import robocup.component.worldobjects.Player;

/**
 * @author Thomas Karbe
 * 
 */
public class TestScoring
    extends GraphicalTestFrame {
  
  Player shooter;
  Ball ball;
  LinkedList<Player> opponents;
  Player oppGoalie;
  PossibleBallsAfterPoweredAcc possBalls;
  ReachableArea goalieRA;
  LinkedList<ReachableArea> oppRAList;
  ShotEvaluatorResults results;

  final Circle leftPostCirc= new Circle(GOAL_POST_LEFT, 0.1);
  final Circle rightPostCirc= new Circle(GOAL_POST_RIGHT, 0.1);

  final LineSegment                     outline                  = new LineSegment(
                                                                     new Vektor(
                                                                         Vektor.XY,
                                                                         SConf
                                                                             .getInstance().half_width,
                                                                         SConf
                                                                             .getInstance().half_length),
                                                                     new Vektor(
                                                                         Vektor.XY,
                                                                         -SConf
                                                                             .getInstance().half_width,
                                                                         SConf
                                                                             .getInstance().half_length));
  final LineSegment                     leftGoalLine             = new LineSegment(
                                                                     SConf
                                                                         .getInstance().GOAL_POST_LEFT_OTHER
                                                                         .cloned(),
                                                                     SConf
                                                                         .getInstance().GOAL_POST_LEFT_OTHER
                                                                         .add(new Vektor(
                                                                             30,
                                                                             0)));
  final LineSegment                     rightGoalLine            = new LineSegment(
                                                                     SConf
                                                                         .getInstance().GOAL_POST_RIGHT_OTHER
                                                                         .cloned(),
                                                                     SConf
                                                                         .getInstance().GOAL_POST_RIGHT_OTHER
                                                                         .add(new Vektor(
                                                                             30,
                                                                             0)));
  // set posts (with some security)
  private static final Vektor GOAL_POST_LEFT = new Vektor(Vektor.XY,
      -SConf.getInstance().GOAL_WIDTH / 2, SConf.getInstance().half_length);
  private static final Vektor GOAL_POST_BACKLEFT = new Vektor(Vektor.XY,
      -SConf.getInstance().GOAL_WIDTH / 2,
      SConf.getInstance().half_length + 2.5);
  private static final Vektor GOAL_POST_RIGHT = new Vektor(Vektor.XY,
      SConf.getInstance().GOAL_WIDTH / 2, SConf.getInstance().half_length);
  private static final Vektor GOAL_POST_BACKRIGHT = new Vektor(Vektor.XY,
      SConf.getInstance().GOAL_WIDTH / 2,
      SConf.getInstance().half_length + 2.5);
  private double minAngKick;
  private double maxAngKick;


//  /**
//   * @author Thomas Karbe
//   * 
//   */
//  static public final class ShotEvaluatorResults {
//
//    /**
//     * @author Thomas Karbe
//     * 
//     * Indicates if the shotvalue is not used, or goes to goal, or is catched by
//     * opponent, or it isn't yet decided what happens with the shot
//     */
//    enum SHOT_VALUE {
//      /**
//       * the value is not decided yet
//       */
//      UNKNOWN,
//      /**
//       * in goal after
//       */
//      IN,
//      /**
//       * out of field or missed
//       */
//      MISS,
//      /**
//       * cannot reach the goal
//       */
//      NOT_USED
//    }
//
//    private double       minAng;
//    private double       maxAng;
//    private double[]     borders = new double[26];
//    private SHOT_VALUE[] values  = new SHOT_VALUE[25];
//    private int          areas;
//
//    /**
//     * Creates new results
//     */
//    public ShotEvaluatorResults() {
//
//      reset();
//    }
//
//    /**
//     * initializes all values
//     */
//    public final void reset() {
//
//      minAng = -90;
//      maxAng = 90;
//      Arrays.fill(borders, Double.MAX_VALUE);
//      borders[0] = minAng;
//      borders[1] = maxAng;
//      Arrays.fill(values, SHOT_VALUE.NOT_USED);
//      values[0] = SHOT_VALUE.UNKNOWN;
//      areas = 1;
//    }
//
//    /**
//     * Creates new results (minAng must be smaller than maxAng)
//     * 
//     * @param minAng
//     *          the initial min angle
//     * @param maxAng
//     *          the initial max angle
//     */
//    public ShotEvaluatorResults(
//        final double minAng,
//        final double maxAng) {
//
//      reset(minAng, maxAng);
//    }
//
//    /**
//     * initializes the results (minAng must be smaller than maxAng)
//     * 
//     * @param minAng
//     *          the initial min angle
//     * @param maxAng
//     *          the initial max angle
//     */
//    public final void reset(final double minAng,
//        final double maxAng) {
//
//      if (minAng < -90) {
//        throw new IllegalArgumentException();
//      }
//      if (maxAng > 90) {
//        throw new IllegalArgumentException();
//      }
//      if (minAng > maxAng) {
//        this.minAng= 89.9999999;
//        this.maxAng= 90;
//        Arrays.fill(values, SHOT_VALUE.MISS);
//        return;
//      }
//      this.minAng = minAng;
//      this.maxAng = maxAng;
//      Arrays.fill(borders, Double.MAX_VALUE);
//      borders[0] = minAng;
//      borders[1] = maxAng;
//      Arrays.fill(values, SHOT_VALUE.NOT_USED);
//      values[0] = SHOT_VALUE.UNKNOWN;
//      areas = 1;
//    }
//
//    /**
//     * Delivers the region number of the angle. Returns -1 if there is no such
//     * region
//     * 
//     * @param angle
//     *          the angle for that a number is needed
//     * @return the region number of this angle
//     */
//    public final int getAreaNumberForAngle(final double angle) {
//
//      if (angle < minAng || angle > maxAng) {
//        return -1;
//      }
//      for (int i = 1; i <= areas; i++) {
//        if (borders[i] >= angle) {
//          return i - 1;
//        }
//      }
//      return -1;
//    }
//
//    /**
//     * Delivers the SHOT_VALUE of the given area or NOT_USED, if there is no
//     * such area
//     * 
//     * @param area
//     *          the area
//     * @return the shotvalue
//     */
//    public final SHOT_VALUE getShotValue(final int area) {
//
//      if (area >= 0 && area < areas) {
//        return values[area];
//      }
//      return SHOT_VALUE.NOT_USED;
//    }
//
//    /**
//     * Delivers the SHOT_VALUE of the given area or NOT_USED, if there is no
//     * such area
//     * 
//     * @param angle
//     *          the angle
//     * @return the shotvalue
//     */
//    public final SHOT_VALUE getShotValue(final double angle) {
//
//      return getShotValue(getAreaNumberForAngle(angle));
//    }
//
//    /**
//     * Sets the value between startAngle and endAngle to shotValue
//     * 
//     * @param startAngle
//     *          the startAngle
//     * @param endAngle
//     *          the endAngle
//     * @param shotVal
//     *          the shotValue
//     */
//    public final void setAreaOverwriting(double startAngle,
//        double endAngle,
//        final SHOT_VALUE shotVal) {
//
//      if (startAngle < minAng) {
//        startAngle = minAng;
//      }
//      if (endAngle > maxAng) {
//        endAngle = maxAng;
//      }
//      if (startAngle >= endAngle) {
//        throw new IllegalArgumentException();
//      }
//      int startArea = getAreaNumberForAngle(startAngle);
//      int endArea = getAreaNumberForAngle(endAngle);
//      if (startArea == endArea) {
//        if (getShotValue(startArea) == shotVal) {
//          return;
//        }
//        System.arraycopy(borders, startArea + 1, borders, startArea + 3, areas
//            - startArea);
//        borders[startArea + 1] = startAngle;
//        borders[startArea + 2] = endAngle;
//        System.arraycopy(values, startArea, values, startArea + 2, areas
//            - startArea);
//        values[startArea + 1] = shotVal;
//        areas += 2;
//        return;
//      }
//      if (startArea == endArea - 1) {
//        if (getShotValue(startArea) == shotVal) {
//          borders[endArea] = endAngle;
//          return;
//        }
//        if (getShotValue(endArea) == shotVal) {
//          borders[endArea] = startAngle;
//          return;
//        }
//        System.arraycopy(borders, endArea + 1, borders, endArea + 2, areas
//            - endArea);
//        borders[endArea] = startAngle;
//        borders[endArea + 1] = endAngle;
//        System.arraycopy(values, endArea, values, endArea + 1, areas
//            - startArea);
//        values[endArea] = shotVal;
//        areas++;
//        return;
//      }
//      int dist = endArea - startArea;
//      System.arraycopy(borders, endArea + 1, borders, startArea + 3, areas
//          - endArea);
//      borders[startArea + 1] = startAngle;
//      borders[startArea + 2] = endAngle;
//      System.arraycopy(values, endArea, values, startArea + 2, areas - endArea);
//      values[startArea + 1] = shotVal;
//      areas = areas - dist + 2;
//      if (values[startArea + 1] == values[startArea + 2]) {
//        System.arraycopy(borders, startArea + 3, borders, startArea + 2, areas
//            - startArea
//            - 2);
//        System.arraycopy(values, startArea + 2, values, startArea + 1, areas
//            - startArea
//            - 2);
//        areas--;
//      }
//      if (values[startArea] == values[startArea + 1]) {
//        System.arraycopy(borders, startArea + 2, borders, startArea + 1, areas
//            - startArea
//            - 1);
//        System.arraycopy(values, startArea + 1, values, startArea, areas
//            - startArea
//            - 1);
//        areas--;
//      }
//    }
//
//    /**
//     * Sets the value between startAngle and endAngle to shotValue but only at
//     * places where shotvalue was UNKNOWN
//     * 
//     * @param startAngle
//     *          the startAngle
//     * @param endAngle
//     *          the endAngle
//     * @param shotVal
//     *          the shotValue
//     */
//    public final void setUnknownArea(double startAngle,
//        double endAngle,
//        final SHOT_VALUE shotVal) {
//
//      if (shotVal == SHOT_VALUE.UNKNOWN) {
//        return;
//      }
//      if (!Vektor.isAngleBetween(startAngle, minAng, endAngle)
//          && !Vektor.isAngleBetween(startAngle, maxAng, endAngle)
//          && !Vektor.isAngleBetween(minAng, startAngle, maxAng)) {
//        return;
//      }
//      if (startAngle < minAng) {
//        startAngle = minAng;
//      }
//      if (endAngle > maxAng) {
//        endAngle = maxAng;
//      }
//      if (startAngle > endAngle) {
//        throw new IllegalArgumentException();
//      }
//      int startArea = getAreaNumberForAngle(startAngle);
//      int endArea = getAreaNumberForAngle(endAngle);
////      System.out.println("startarea: "+startArea+" startang: "+startAngle);
////      System.out.println("endarea: "+endArea+" endang: "+endAngle);
//      if (startArea == endArea) {
//        if (getShotValue(startArea) != SHOT_VALUE.UNKNOWN) {
//          return;
//        }
////        System.out.println("start == end --> put new area between");
//        System.arraycopy(borders, startArea + 1, borders, startArea + 3, areas
//            - startArea);
//        borders[startArea + 1] = startAngle;
//        borders[startArea + 2] = endAngle;
//        System.arraycopy(values, startArea, values, startArea + 2, areas
//            - startArea);
//        values[startArea + 1] = shotVal;
//        areas += 2;
//        checkSmallAreas();
//        return;
//      }
//      if (values[startArea] == SHOT_VALUE.UNKNOWN
//          && borders[startArea + 1] != startAngle) {
////         have to split it
////        System.out.println("have to split startarea");
////        System.out.println(this);
//        System.arraycopy(borders, startArea + 1, borders, startArea + 2, areas
//            - startArea);
//        borders[startArea + 1] = startAngle;
//        System.arraycopy(values, startArea + 1, values, startArea + 2, areas
//            - startArea
//            - 1);
//        values[startArea + 1] = shotVal;
//        areas++;
//        endArea++;
////        System.out.println(this);
//      }
//      for (int i = startArea + 1; i < endArea; i++) {
//        if (values[i] == SHOT_VALUE.UNKNOWN) {
////          System.out.println("fill value["+i+"]");
////          System.out.println(this);
//          values[i] = shotVal;
////          System.out.println(this);
//        }
//      }
//      if (values[endArea] == SHOT_VALUE.UNKNOWN
//          && borders[endArea + 1] != endAngle) {
////        System.out.println("have to split endarea");
////        System.out.println(this);
//        // have to split it
//        System.arraycopy(borders, endArea + 1, borders, endArea + 2, areas
//            - endArea);
//        borders[endArea + 1] = endAngle;
//        System.arraycopy(values, endArea, values, endArea+1, areas - endArea);
//        values[endArea] = shotVal;
//        areas++;
////        System.out.println(this);
//      }
//      if (values[endArea] == SHOT_VALUE.UNKNOWN
//          && borders[endArea + 1] == endAngle) {
////        System.out.println("set last area");
////        System.out.println(this);
//        values[endArea] = shotVal;
////        System.out.println(this);
//      }
//
//      // connect same shotvalues
//      for (int i = areas - 1; i > 0; i--) {
//        if (values[i] == values[i - 1]) {
////          System.out.println("connect same areas");
////          System.out.println(this);
//          System.arraycopy(values, i + 1, values, i, areas - i - 1);
//          System.arraycopy(borders, i + 1, borders, i, areas - i);
//          areas--;
////          System.out.println(this);
//        }
//      }
//      checkSmallAreas();
//    }
//
//    private final void checkSmallAreas() {
//
//      for (int i = areas; i > 1; i--) {
//        if (borders[i] - borders[i - 1] < 0.00005) {
//          System.arraycopy(borders, i, borders, i - 1, areas - i + 1);
//          System.arraycopy(values, i, values, i - 1, areas - i);
//          areas--;
//        }
//      }
//      if (borders[1] - borders[0] < 0.00005) {
//        System.arraycopy(borders, 2, borders, 1, areas - 1);
//        System.arraycopy(values, 1, values, 0, areas - 1);
//        areas--;
//      }
//    }
//
//    /**
//     * checks if an area is unknown
//     * 
//     * @return true if no area is unknown
//     */
//    public final boolean complete() {
//
//      for (int i = 0; i < areas; i++) {
//        if (values[i] == SHOT_VALUE.UNKNOWN) {
//          return false;
//        }
//      }
//      return true;
//    }
//
//    /**
//     * gives the best shot angle or Double.MAX_VALUE if there is no possible
//     * shot
//     * 
//     * @return the best shot angle
//     */
//    public final double getBestAngle() {
//
//      double bestDiff = 0;
//      double bestAng = 0;
//      for (int i = 0; i < areas; i++) {
//        if (values[i] == SHOT_VALUE.IN) {
//          if (borders[i + 1] - borders[i] > bestDiff) {
//            bestAng = (borders[i + 1] + borders[i]) / 2;
//            bestDiff = borders[i + 1] - borders[i];
//          }
//        }
//      }
//      if (bestDiff > 0) {
//        return bestAng;
//      }
//      return Double.MAX_VALUE;
//    }
//
//    /**
//     * gives the space for the best shot angle
//     * 
//     * @return the space
//     */
//    public final double getBestSpace() {
//
//      double bestDiff = 0;
//      for (int i = 0; i < areas; i++) {
//        if (values[i] == SHOT_VALUE.IN) {
//          if (borders[i + 1] - borders[i] > bestDiff) {
//            bestDiff = borders[i + 1] - borders[i];
//          }
//        }
//      }
//      return bestDiff;
//    }
//
//    /**
//     * Returns an array with all areas of the given shotValue
//     * 
//     * @param val
//     *          the needed value
//     * @return an array of area-numbers
//     */
//    public final int[] getAreasWithValue(final SHOT_VALUE val) {
//
//      int i = 0;
//      for (int j = 0; j < areas; j++) {
//        if (values[j] == val) {
//          i++;
//        }
//      }
//      int[] arr = new int[i];
//      i = 0;
//      for (int j = 0; j < areas; j++) {
//        if (values[j] == val) {
//          arr[i] = j;
//        }
//      }
//      return arr;
//    }
//
//    /**
//     * Returns the startAngle of the area or Double.MAX_VALUE if the area
//     * doesn't exist
//     * 
//     * @param area
//     *          the number of the area
//     * @return the start angle
//     */
//    public final double getStartAngle(final int area) {
//
//      if (area < areas && area >= 0) {
//        return borders[area];
//      }
//      return Double.MAX_VALUE;
//    }
//
//    /**
//     * Returns the endAngle of the area or Double.MAX_VALUE if the area doesn't
//     * exist
//     * 
//     * @param area
//     *          the number of the area
//     * @return the end angle
//     */
//    public final double getEndAngle(final int area) {
//
//      if (area < areas && area >= 0) {
//        return borders[area + 1];
//      }
//      return Double.MAX_VALUE;
//    }
//
//    /**
//     * @return the maximum angle that can be examined
//     */
//    public final double getMaxAng() {
//
//      return maxAng;
//    }
//
//    /**
//     * @return the minimum angle that can be examined
//     */
//    public final double getMinAng() {
//
//      return minAng;
//    }
//
//    /**
//     * set all values that haven't been examined to MISS
//     */
//    public final void setComplete() {
//
//      for (int i = 0; i < areas; i++) {
//        if (values[i] == SHOT_VALUE.UNKNOWN) {
//          values[i] = SHOT_VALUE.MISS;
//        }
//      }
//    }
//
//    /**
//     * (non-Javadoc)
//     * 
//     * @see java.lang.Object#toString()
//     */
//    public final String toString() {
//
//      StringBuffer sb = new StringBuffer();
//      sb.append("areas: ").append(areas).append(" minAng: ").append(minAng)
//          .append(" maxAng: ").append(maxAng);
//      sb.append(" borders: ").append(Arrays.toString(borders)).append(
//          " values: ").append(Arrays.toString(values));
//      return sb.toString();
//    }
//
//    
//    /**
//     * Returns the number of areas
//     * @return the number of areas
//     */
//    public int getAreas() {
//    
//      return areas;
//    }
//
//  }

  /**
   * 
   */
  public TestScoring() {

    super();
  }

  /**
   * @param d
   */
  public TestScoring(
      Dimension d) {

    super(d);
  }

  /**
   * @param center
   */
  public TestScoring(
      Vektor center) {

    super(center);
  }

  /**
   * @param d
   * @param center
   */
  public TestScoring(
      Dimension d,
      Vektor center) {

    super(d, center);
  }

  /**
   * @param scale
   */
  public TestScoring(
      double scale) {

    super(scale);
  }

  /**
   * @param d
   * @param scale
   */
  public TestScoring(
      Dimension d,
      double scale) {

    super(d, scale);
  }

  /**
   * @param center
   * @param scale
   */
  public TestScoring(
      Vektor center,
      double scale) {

    super(center, scale);
  }

  /**
   * @param d
   * @param center
   * @param scale
   */
  public TestScoring(
      Dimension d,
      Vektor center,
      double scale) {

    super(d, center, scale);
  }

  /**
   * (non-Javadoc)
   * 
   * @see robocup.testing.GraphicalTestFrame#nextSituation()
   */
  @Override
  protected void nextSituation() {
    initObjects();
    initResults();
    calcShotPosts();
    calcShotInOut();
    calcCatchOpponents();
  }

  private void calcCatchOpponents() {
    for (int index = 0; index < opponents.size(); index++) {
      if (results.complete()) {
        break;
      }
//      if (!relevantOpponents[index]) {
//        continue;
//      }
//      ra.setArea(cycle, Math.min(0, playerOffset[index]),
//          opponents.get(index),
//          (opponents.get(index).isGoalie() ? opponents(index)
//              .getCatchDistance() : opponents.get(index)
//              .getKickDistance())
//              + Math.max(0, playerOffset[index]));
      if (!results.complete()) {
        LinkedList<Vektor> list = possBalls.getIntersectionPoints(oppRAList.get(index), true);
        possBalls.filterShortPoints(list);
        for (int i = list.size() - 1; i >= 0; i--) {
          if (Math.abs(ball.getAngleTo(list.get(i))) > 90) {
            list.remove(i);
          }
        }
        double[] angles = new double[list.size() + 2];
        angles[0] = minAngKick;
        angles[1] = maxAngKick;
        for (int i = 2; i < angles.length; i++) {
          angles[i] = ball.getAngleTo(list.get(i - 2));
        }
        Arrays.sort(angles);
        for (int i = 0; i < angles.length - 1; i++) {
          Vektor center = possBalls
              .getPointForShotAngleAbs((angles[i] + angles[i + 1]) / 2);
          if (oppRAList.get(index).inArea(center, true)) {
            results.setUnknownArea(angles[i], angles[i + 1],
                SHOT_VALUE.MISS_OPP);
          }
        }
      }
    }
  }

  private void calcShotPosts() {
    if (!results.complete()) {
      leftPostCirc.setRadius(0.1 + 0.02 * goalieRA.getCycles());
      rightPostCirc.setRadius(0.1 + 0.02 * goalieRA.getCycles());

      LinkedList<Vektor> list = possBalls
          .getIntersectionPoints(leftPostCirc);
      possBalls.filterShortPoints(list);
      for (int i = list.size() - 1; i >= 0; i--) {
        if (Math.abs(ball.getAngleTo(list.get(i))) > 90) {
          list.remove(i);
        }
      }
      double[] angles = new double[list.size() + 2];
      angles[0] = minAngKick;
      angles[1] = maxAngKick;
      for (int i = 2; i < angles.length; i++) {
        angles[i] = ball.getAngleTo(list.get(i - 2));
      }
      Arrays.sort(angles);
      for (int i = 0; i < angles.length - 1; i++) {
        Vektor center = possBalls
            .getPointForShotAngleAbs((angles[i] + angles[i + 1]) / 2);
        if (leftPostCirc.getCenter().getDistance(center) <= leftPostCirc.getRadius()) {
          results.setUnknownArea(angles[i], angles[i + 1],
              SHOT_VALUE.MISS_OUT);
        }
      }

      list = possBalls.getIntersectionPoints(rightPostCirc);
      possBalls.filterShortPoints(list);
      for (int i = list.size() - 1; i >= 0; i--) {
        if (Math.abs(ball.getAngleTo(list.get(i))) > 90) {
          list.remove(i);
        }
      }
      angles = new double[list.size() + 2];
      angles[0] = minAngKick;
      angles[1] = maxAngKick;
      for (int i = 2; i < angles.length; i++) {
        angles[i] = ball.getAngleTo(list.get(i - 2));
      }
      Arrays.sort(angles);
      for (int i = 0; i < angles.length - 1; i++) {
        Vektor center = possBalls
            .getPointForShotAngleAbs((angles[i] + angles[i + 1]) / 2);
        if (rightPostCirc.getCenter().getDistance(center) <= leftPostCirc.getRadius()) {
          results.setUnknownArea(angles[i], angles[i + 1],
              SHOT_VALUE.MISS_OUT);
        }
      }
    }
  }

  private void calcShotInOut() {
    if (results.complete()) {
      return;
    }
    LinkedList<Vektor> list = possBalls.getIntersectionPoints(outline);
    possBalls.addIntersectionPointsToList(leftGoalLine, list);
    possBalls.addIntersectionPointsToList(rightGoalLine, list);
    possBalls.filterShortPoints(list);
    for (int i = list.size() - 1; i >= 0; i--) {
      if (Math.abs(ball.getAngleTo(list.get(i))) > 90) {
        list.remove(i);
      }
    }
    double[] outAngles = new double[list.size() + 2];
    outAngles[0] = minAngKick;
    outAngles[1] = maxAngKick;
    for (int i = 2; i < outAngles.length; i++) {
      outAngles[i] = ball.getAngleTo(list.get(i - 2));
    }
    Arrays.sort(outAngles);

    for (int outIndex = 0; outIndex < outAngles.length - 1; outIndex++) {
      Vektor outCenter = possBalls
          .getPointForShotAngleAbs((outAngles[outIndex] + outAngles[outIndex + 1]) / 2);
      if (outCenter.y > SConf.getInstance().half_length) {
        double goalAngle1 = outAngles[outIndex];
        double goalAngle2 = outAngles[outIndex + 1];
        if (Math.abs(outCenter.x) > GOAL_POST_RIGHT.x) {
          results.setUnknownArea(goalAngle1, goalAngle2,
              SHOT_VALUE.MISS_OUT);
        }
        else {
          results.setUnknownArea(goalAngle1, goalAngle2,
              SHOT_VALUE.IN);
        }
      }
    }
  }

  private void initObjects() {
    setCenter(new Vektor(Vektor.XY, 0, 45));
    shooter= rand.getRandomPlayer(-15, 15, 35, 50);
    ball= rand.getRandomBallInKickable(shooter);
    possBalls= new PossibleBallsAfterPoweredAcc(shooter, ball);
    oppGoalie= rand.getRandomGoalie(-8, 8, 45, 53);
    oppGoalie.setFriend(false);
    goalieRA= new ReachableArea(1, oppGoalie, oppGoalie.getCatchDistance());
    int numberOpps= rand.getRandomInt(1, 5);
    opponents= new LinkedList<Player>();
    oppRAList= new LinkedList<ReachableArea>();
    for (int i= 0; i < numberOpps; i++) {
      opponents.add(rand.getRandomPlayer(-15, 15, 35, 50));
      opponents.get(i).setFriend(false);
      oppRAList.add(new ReachableArea(1, opponents.get(i), opponents.get(i).getKickDistance()));
    }
    opponents.add(oppGoalie);
    oppRAList.add(goalieRA);
  }

  private void initResults() {
    
    results= new ShotEvaluatorResults();
    double minAng = ball.getAngleTo(GOAL_POST_LEFT);
    double maxAng = ball.getAngleTo(GOAL_POST_RIGHT);
    if (ball.getPosition().x < GOAL_POST_LEFT.x) {
      minAng = ball.getAngleTo(GOAL_POST_BACKLEFT);
    }
    else if (ball.getPosition().x > GOAL_POST_RIGHT.x) {
      maxAng = ball.getAngleTo(GOAL_POST_BACKRIGHT);
    }
    minAngKick = possBalls.getMinAngle();
    maxAngKick = possBalls.getMaxAngle();
    System.out.println(possBalls);
    System.out.println(possBalls.getMinAngle());
    System.out.println(possBalls.getMaxAngle());
    if (maxAngKick > 90) {
      if (maxAngKick >= minAngKick) {
        if (minAngKick >= -90 && minAngKick <= 90) {
          maxAngKick = 90;
        }
        else if (minAngKick > 90) {
          maxAngKick = 90;
          minAngKick = 90;
        }
        else {
          maxAngKick = 90;
          minAngKick = -90;
        }
      }
    }
    else if (maxAngKick >= -90 && maxAngKick <= 90) {
      if (minAngKick <= maxAngKick) {
        if (minAngKick < -90) {
          minAngKick = -90;
        }
      }
      else {
        minAngKick = -90;
      }
    }
    else {
      if (minAngKick <= maxAngKick) {
        minAngKick = -90;
        maxAngKick = -90;
      }
      else {
        if (minAngKick >= -90 && minAngKick <= 90) {
          maxAngKick = 90;
        }
        else {
          minAngKick = -90;
          maxAngKick = -90;
        }
      }
    }
    results.reset(Math.max(minAng, minAngKick), Math.min(maxAng,maxAngKick));
  }

  /**
   * (non-Javadoc)
   * 
   * @see robocup.testing.GraphicalTestFrame#nextCycle()
   */
  @Override
  protected void nextCycle() {
    possBalls.extrapolateThis();
    goalieRA.setArea(goalieRA.getCycles()+1, oppGoalie, oppGoalie.getCatchDistance());
    for (int i= 0; i < oppRAList.size(); i++) {
      oppRAList.get(i).setArea(goalieRA.getCycles(), opponents.get(i), opponents.get(i).getKickDistance());
    }
    goalieRA.setArea(goalieRA.getCycles(), oppGoalie, oppGoalie.getCatchDistance());
    calcShotPosts();
    calcShotInOut();
    calcCatchOpponents();
  }

  /**
   * (non-Javadoc)
   * 
   * @see robocup.testing.GraphicalTestFrame#paintSituation(java.awt.Graphics)
   */
  @Override
  protected void paintSituation(Graphics g) {
    g.setColor(Color.BLACK);
    drawOppPenalty(g);
    g.setColor(Color.red);
    drawKickable(g, shooter);
    drawMovement(g, ball);
    drawMovement(g, oppGoalie);
    drawMovement(g, shooter);
    for (Player p: opponents) {
      drawMovement(g, p);
      draw(g,p);
    }
    g.setColor(Color.ORANGE);
    draw(g,oppGoalie);
    g.setColor(Color.YELLOW);
    draw(g,shooter);
    g.setColor(Color.BLACK);
    draw(g,ball);
    for (ReachableArea ra: oppRAList) {
      draw(g, ra, true);
    }
    draw(g, goalieRA, true);
    g.setColor(Color.BLUE);
    draw(g,possBalls);
    draw(g, results, ball);
  }

  /**
   * @param args
   */
  public static void main(String[] args) {
    new TestScoring(new Dimension(1050,700),0.5);
  }

}
